package com.jplus.core.utill;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.WildcardType;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.Stack;

/**
 * 
 * JSON 工具类
 * 
 * @TODO 反序列化实体的性能比反射成JSONObject,JSONArray的性能差6倍;
 * @TODO 反序列化实体的性能比 fastJson 的性能差10倍；
 * @TODO 序列化的性能比fastJson 的性能差2倍；
 * @TODO 在优化缓存中...针对反射设置了Method,Field,Type的缓存，发现反而更慢，看来JDK已经做了优化
 */
public class JSON {

	private static int DEPTH = 10;
	private static String DEFFAULT_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
	private static ConvertUtil CONVERT = ConvertUtil.newInstance();

	private static final String SP = "\"";
	private static final char[] CP1 = { '\f', '\n', '\r', '\t', '\b' };
	private static final String[] CP2 = { "\\f", "\\n", "\\r", "\\t", "\\b" };

	/**
	 * 【自定义】 递归层级
	 */
	public static void setDefDepth(int depth) {
		Assert.isTrue(depth >= 1, " depth can not less than 1.");
		JSON.DEPTH = depth;
	}

	/**
	 * 【自定义】 日期格式
	 */
	public static void setDefDateFormat(String dateFormat) {
		Assert.notNull(dateFormat, "datePattern can not be blank.");
		JSON.CONVERT.setDefDateFormat(dateFormat);
		JSON.DEFFAULT_DATE_FORMAT = dateFormat;
	}

	/**
	 * 【自定义】转换器
	 */
	public static void setDefConvert(ConvertUtil convert) {
		JSON.CONVERT = convert;
	}

	/**
	 * =================================================================================
	 * 将对象 转为JSON字符串
	 * =================================================================================
	 */
	public static String toJSONString(Object value) {
		return escape(toJSON(value, DEPTH));
	}

	/**
	 * 将对象 转为JSON字符串
	 */
	private static String toJSON(Object value, int depth) {
		String res = CONVERT.custom(value);
		// 值类型:对象、数组、数字、字符串或者三个字面值(false、null、true)中的一个,字面值必须小写。
		if (res != null)
			return res;
		if (value == null || (depth--) < 0) // 字面值:null
			return "null";
		if (value instanceof String)// 字符串
			return new StringBuilder().append(SP).append(value).append(SP).toString();
		if (value instanceof Number)// 数字
			return value.toString();
		if (value instanceof Boolean)// 字面值:true/false
			return (boolean) value == true ? "true" : "false";
		if (value instanceof java.util.Date)
			return toJSON(new SimpleDateFormat(DEFFAULT_DATE_FORMAT).format(value), depth);
		if (value instanceof Map)// 对象
			return mapToJson((Map<?, ?>) value, depth);
		if (value instanceof List)// 数组
			return listToJson((List<?>) value, depth);
		if (value instanceof Object[])
			return listToJson(Arrays.asList((Object[]) value), depth);
		if (value instanceof Enum)
			return toJSON(((Enum<?>) value).toString(), depth);
		if (value instanceof Class)
			return toJSON(((Class<?>) value).getName(), depth);
		return beanToJson(value, depth);
	}

	private static String mapToJson(Map<?, ?> map, int depth) {
		StringBuilder sb = new StringBuilder();
		Iterator<?> iter = map.entrySet().iterator();
		sb.append('{');
		int index = 0;
		while (iter.hasNext()) {
			if (index++ > 0)
				sb.append(',');
			Map.Entry<?, ?> entry = (Entry<?, ?>) iter.next();
			sb.append(toJSON(entry.getKey(), depth));
			sb.append(":");
			sb.append(toJSON(entry.getValue(), depth));
		}
		sb.append('}');
		return sb.toString();
	}

	private static String listToJson(List<?> list, int depth) {
		StringBuilder sb = new StringBuilder();
		Iterator<?> iter = list.iterator();
		sb.append('[');
		int index = 0;
		while (iter.hasNext()) {
			if (index++ > 0)
				sb.append(',');
			Object value = iter.next();
			sb.append(toJSON(value, depth));
		}
		sb.append(']');
		return sb.toString();
	}

	private static String beanToJson(Object bean, int depth) {
		Map<String, Object> map = new HashMap<>();
		try {
			Field[] fields = bean.getClass().getFields();
			for (Field f : fields) {
				f.setAccessible(true);
				f.get(bean);
				map.put(f.getName(), f.get(bean));
			}
			Method[] methods = bean.getClass().getMethods();
			for (Method m : methods) {
				m.setAccessible(true);
				String methodName = m.getName();
				String fieldName = "";
				int len = methodName.length();
				if (methodName.startsWith("get") && len > 3) { // getXXX
					if (methodName.equals("getClass"))// Ignore Object.getClass()
						continue;
					fieldName = methodName.substring(3);
				} else if (methodName.startsWith("is") && len > 2) { // isXXX
					fieldName = methodName.substring(2);
				}
				if (fieldName.length() > 0 && map.get(fieldName) == null && m.getParameterTypes().length == 0) {
					Object value = m.invoke(bean);
					map.put(firstCharToLowerCase(fieldName), value);
				}
			}
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
		return

		mapToJson(map, depth);
	}

	/**
	 * 转义 字符
	 */
	private static String escape(String s) {
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < s.length(); i++)
			sb.append(get(s.charAt(i)));
		return sb.toString();
	}

	private static String get(char c) {
		for (int i = 0; i < CP1.length; i++)
			if (CP1[i] == c)
				return CP2[i];
		return String.valueOf(c);
	}

	/**
	 * =================================================================================
	 * 将JSON字符串 转为对象/集合
	 * =================================================================================
	 */
	public static JSONObject parseObject(String jsonStr) {
		return (JSONObject) parse(jsonStr);
	}

	public static JSONArray parseArray(String jsonStr) {
		return (JSONArray) parse(jsonStr);
	}

	/**
	 * 将 JSON 转 Object
	 */
	private static Object parse(String jsonStr) {
		String EOF = "|";// 结构体标识
		Boolean is = Boolean.FALSE; // 当前是否为字符串
		Stack<Character> s1 = new Stack<Character>();// 栈：符号 {[,:]}
		Stack<Object> s2 = new Stack<Object>();// 栈：值
		StringBuffer sb = new StringBuffer();
		char[] jsonArr = jsonStr.toCharArray();
		for (int i = 0; i < jsonArr.length; i++) {
			char c = jsonArr[i];
			switch (c) {
			case '{':
			case '[':
				s1.add(c);
				s2.add(EOF);
				break;
			case ']':
			case '}':
				if (!is) {
					putValue(sb, s2, jsonArr[i - 1] == '"');
					char ls2 = s1.pop();
					int x = i - 50 < 0 ? 0 : i - 50;// useless
					Assert.isTrue((c == '}' && ls2 == '{') || (c == ']' && ls2 == '['),
							"JSON Format ERROR,near :" + jsonStr.substring(x, i));
					Object obj = null;
					// >> Begin >>>
					if (c == '}') {// map
						JSONObject jobj = new JSONObject();
						while (!s2.isEmpty() && !EOF.equals(s2.peek())) {
							Object v = s2.pop();// 先
							Object k = s2.pop();// 后
							jobj.put(k.toString(), v);
						}
						obj = jobj;
					}
					if (c == ']') {// list
						JSONArray jarr = new JSONArray();
						while (!s2.isEmpty() && !EOF.equals(s2.peek()))
							jarr.add(0, s2.pop());// 按顺序
						obj = jarr;
					}
					// >> End >>>
					s2.pop();
					s2.add(obj);
					break;
				}
			case ':':
			case ',':
				if (!is) {
					putValue(sb, s2, jsonArr[i - 1] == '"');
					break;
				}
			case '"':
				if (c == '"' && jsonArr[i - 1] != '\\') {
					is = !is;
					break;
				}
			default:
				sb.append(c);
				break;
			}
		}
		Assert.isTrue(s1.isEmpty(), "JSON Non-closed state,Please check the format.");
		return s2.pop();
	}

	private static void putValue(StringBuffer sb, Stack<Object> s2, boolean isStr) {
		if (sb.length() > 0) {
			String str = sb.toString().trim();
			Object val = str;
			if (!isStr) {// 非String
				if (isNumber(false, str))// 数字
					val = Long.valueOf(str);
				else if (isNumber(true, str))// 浮点数
					val = Double.parseDouble(str);
				else if ((str).equals("null")) // null
					val = null;
				else if ((str).equals("true")) // boolean
					val = true;
				else if ((str).equals("false"))
					val = false;
			}
			s2.add(val);
			sb.setLength(0);
		}
	}

	/**
	 * =================================================================================
	 * 将JSON转为 Bean
	 * =================================================================================
	 */
	@SuppressWarnings("unchecked")
	public static <T> T parseBean(String json, Class<T> clazz) {
		return (T) parseBean(parse(json), clazz);
	}

	@SuppressWarnings("unchecked")
	public static <T> T parseBean(String json, TypeReference<T> clazz) {
		return (T) parseBean(parse(json), clazz.getType());
	}

	@SuppressWarnings("unchecked")
	public static <T> T parseBean(JSONObject json, Class<T> clazz) {
		return (T) parseBean((Object) json, clazz);
	}

	@SuppressWarnings("unchecked")
	public static <T> T parseBean(JSONArray json, Class<T> clazz) {
		return (T) parseBean((Object) json, clazz);
	}

	/**
	 * 将JSON 转为 JavaBean
	 */
	protected static Object parseBean(Object json, Type type) {
		if (json == null)
			return null;
		Class<?> clazz = convertCla(type);
		Assert.notNull(clazz, "The argument resolves to null：" + type);
		if (List.class.isAssignableFrom(clazz)) {// List
			JSONArray temp = new JSONArray();
			for (Object object : (JSONArray) json)
				temp.add(parseBean(object, ((ParameterizedType) type).getActualTypeArguments()[0]));
			return temp;
		} else if (Map.class.isAssignableFrom(clazz)) {// Map
			JSONObject temp = ((JSONObject) json);
			Iterator<Entry<String, Object>> imap = temp.entrySet().iterator();
			while (imap.hasNext()) {
				Entry<String, Object> en = imap.next();
				en.setValue(parseBean(en.getValue(), ((ParameterizedType) type).getActualTypeArguments()[1]));
			}
			return temp;
		} else if (json instanceof Map) {// 实体bean
			try {
				Object obj = newInstance(clazz);
				Method[] ms = clazz.getMethods();
				Field[] fs = clazz.getFields();
				Set<Entry<String, Object>> setMap = ((JSONObject) json).entrySet();
				for (Map.Entry<?, ?> en : setMap) {
					String k = en.getKey().toString();
					Object v = en.getValue();
					for (Method m : ms) {
						if (m.getName().equals("set" + firstCharToUpperCase(k))) {
							m.setAccessible(true);
							Type t1 = m.getGenericParameterTypes()[0];
							if (convertCla(t1) == null)
								t1 = ((ParameterizedType) type).getActualTypeArguments()[0];
							else if (equalsType(t1, type))
								t1 = type;
							Object args = parseBean(v, t1);
							m.invoke(obj, args);
							break;
						}
					}
					for (Field f : fs) {
						if (k.equals(f.getName())) {
							f.setAccessible(true);
							Type t1 = f.getGenericType();
							if (convertCla(t1) == null)
								t1 = ((ParameterizedType) type).getActualTypeArguments()[0];
							else if (equalsType(t1, type))
								t1 = type;
							f.set(obj, parseBean(v, t1));
							break;
						}
					}

				}
				return obj;
			} catch (Exception e) {
				e.printStackTrace();
				throw new RuntimeException(e);
			}
		} else { // 基本数据类型
			return CONVERT.convert(String.valueOf(json), clazz);
		}
	}

	private static boolean equalsType(Type t1, Type t2) {
		if (t1 instanceof ParameterizedType && t2 instanceof ParameterizedType)
			return (((ParameterizedType) t1).getRawType().equals(((ParameterizedType) t2).getRawType())) ? true : false;
		return t1.equals(t2);
	}

	private static Class<?> convertCla(Type type) {
		if (type instanceof Class) {
			return (Class<?>) type;
		} else if (type instanceof ParameterizedType) {
			return convertCla(((ParameterizedType) type).getRawType());
		} else if (type instanceof WildcardType) {
			WildcardType wildcardType = (WildcardType) type;
			Type[] upperBounds = wildcardType.getUpperBounds();
			if (upperBounds.length == 1) {
				Type upperBoundType = upperBounds[0];
				return convertCla(upperBoundType);
			}
		}
		return null;
	}

	private static Object newInstance(Class<?> clazz) throws NoSuchMethodException, SecurityException,
			InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
		if (clazz.isInterface()) {// 接口
			throw new RuntimeException("You must specify the concrete interface implementation class：" + clazz);
			// ClassLoader loader = Thread.currentThread().getContextClassLoader();
			// JSONObject obj = new JSONObject();
			// Object proxy = Proxy.newProxyInstance(loader, new Class<?>[] { clazz }, obj);
			// return proxy;
		} else {
			Constructor<?> cons = clazz.getConstructor();// 无参构造
			return cons.newInstance();
		}
	}

	/**
	 * =================================================================================
	 * 格式化JSON字符串
	 * =================================================================================
	 */
	public static String format(String json) {
		Object obj = parse(json);
		return format(obj, PLACE);
	}

	final static String PLACE = "    ";// 四个空格

	private static String format(Object obj, String indent) {
		StringBuilder sb = new StringBuilder();
		if (obj instanceof List) {
			JSONArray jarr = (JSONArray) obj;
			sb.append("[\n");
			int x = jarr.size();
			for (Object object : jarr) {
				sb.append(indent + format(object, indent + PLACE));
				if (--x > 0)
					sb.append(",");
				sb.append("\n");
			}
			int p = indent.length() - PLACE.length();
			sb.append(indent.substring(0, p > 0 ? p : 0) + "]");
		} else if (obj instanceof Map) {
			JSONObject jobj = (JSONObject) obj;
			sb.append("{\n");
			int x = jobj.size();
			for (Entry<String, Object> en : jobj.entrySet()) {
				sb.append(indent + format(en.getKey(), indent) + ": " + format(en.getValue(), indent + PLACE));
				if (--x > 0)
					sb.append(",");
				sb.append("\n");
			}
			int p = indent.length() - PLACE.length();
			sb.append(indent.substring(0, p > 0 ? p : 0) + "}");
		} else if (obj instanceof String) {
			sb.append("\"" + obj + "\"");
		} else if (obj == null) {
			sb.append("null");
		} else {
			sb.append(obj.toString());
		}
		return sb.toString();
	}

	// ==工具=================================================================================
	private static boolean isNumber(boolean isfloat, String str) {
		if (str == null || str.length() == 0)
			return false;
		byte[] bts = str.getBytes();
		int index = 0;// 位置计数
		int fsize = 0;// 浮点数计数
		for (byte b : bts) {
			// (首位为负 || 0~9 || 非首位有一个点)// 判断顺序很重要
			if ((index++ == 0 && b == '-') || (b >= '0' && b <= '9') || (isfloat && b == '.' && fsize++ == 0))
				continue;
			return false;
		}
		return true;
	}

	private static String firstCharToLowerCase(String str) {
		return Character.toLowerCase(str.charAt(0)) + str.substring(1);
	}

	private static String firstCharToUpperCase(String str) {
		return Character.toUpperCase(str.charAt(0)) + str.substring(1);
	}

	// == 辅助类 ====================================================================
	public static class JSONObject extends HashMap<String, Object> {
		private static final long serialVersionUID = 1L;

		@SuppressWarnings("unchecked")
		public <T> T getBean(String key, Class<T> clazz) {
			return (T) parseBean(get(key), clazz);
		}

		public JSONArray getJSONArray(String key) {
			return (JSONArray) get(key);
		}

		public JSONObject getJSONObject(String key) {
			return (JSONObject) get(key);
		}

		public String toJSONString() {
			return JSON.toJSONString(this);
		}

		public Integer getInt(String key) {
			return Integer.parseInt(getString(key));
		}

		public String getString(String key) {
			return get(key).toString();
		}

		public Double getDouble(String key) {
			return Double.parseDouble(getString(key));
		}

		public Boolean getBoolean(String key) {
			return Boolean.parseBoolean(getString(key));
		}
	}

	public static class JSONArray extends ArrayList<Object> {
		private static final long serialVersionUID = 1L;

		@SuppressWarnings("unchecked")
		public <T> T getBean(int index, Class<T> clazz) {
			return (T) parseBean(get(index), clazz);
		}

		public JSONArray getJSONArray(int index) {
			return (JSONArray) get(index);
		}

		public JSONObject getJSONObject(int index) {
			return (JSONObject) get(index);
		}

		public String toJSONString() {
			return JSON.toJSONString(this);
		}

		public Integer getInt(int index) {
			return Integer.parseInt(getString(index));
		}

		public String getString(int index) {
			return get(index).toString();
		}

		public Double getDouble(int index) {
			return Double.parseDouble(getString(index));
		}

		public Boolean getBoolean(int index) {
			return Boolean.parseBoolean(getString(index));
		}
	}

	/**
	 * 泛型对象包装类
	 */
	public static class TypeReference<T> {
		protected Type type;

		public Type getType() {
			return type;
		}

		protected TypeReference() {
			super();
			Type superClass = this.getClass().getGenericSuperclass();
			Type type = ((ParameterizedType) superClass).getActualTypeArguments()[0];
			Type cachedType = (type);
			this.type = cachedType;
		}
	}

	public static enum OPERATE {
		// 转JSON,转Bean, 转集合
		TOJSON, TOBEAN, TOOBJ;
	}

}
